﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using Microsoft.Win32;

using 地圖檔案序列化;

using Microsoft.Kinect;
using Microsoft.Kinect.Toolkit;
using Microsoft.Kinect.Toolkit.Controls;
using Kinect.Toolbox;
using Kinect.Toolbox.Record;



namespace FizzGame
{
    public partial class GamePage : Page
    {
        KinectSensor kinectSensor;
        readonly ColorStreamManager colorManager = new ColorStreamManager();
        readonly DepthStreamManager depthManager = new DepthStreamManager();
        private Skeleton[] skeletons;
        readonly AlgorithmicPostureDetector algorithmicPostureRecognizer = new AlgorithmicPostureDetector();
        readonly ContextTracker contextTracker = new ContextTracker();
        private void GamePage_Loaded(object sender, RoutedEventArgs e)
        {
            Keyboard.Focus(NGamePage);
            try
            {
                KinectSensor.KinectSensors.StatusChanged += Kinects_StatusChanged;//loop through all the Kinects attached to this PC, and start the first that is connected without an error.
                foreach (KinectSensor kinect in KinectSensor.KinectSensors)
                {
                    if (kinect.Status == KinectStatus.Connected)
                    {
                        kinectSensor = kinect;
                        break;
                    }
                }
                if (KinectSensor.KinectSensors.Count == 0)
                    MessageBox.Show("No Kinect found");
                else
                    Initialize();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private void Initialize()
        {
     //       MessageBox.Show("Kinect Connect");
            if (kinectSensor == null)
                return;

            kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters
            {
                Smoothing = 0.5f,
                Correction = 0.5f,
                Prediction = 0.5f,
                JitterRadius = 0.05f,
                MaxDeviationRadius = 0.04f
            });
            kinectSensor.SkeletonFrameReady += kinectRuntime_SkeletonFrameReady;
            kinectSensor.Start();
        }
        void Kinects_StatusChanged(object sender, StatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case KinectStatus.Connected:
                    if (kinectSensor == null)
                    {
                        kinectSensor = e.Sensor;
                        Initialize();
                    }
                    break;
                case KinectStatus.Disconnected:
                    if (kinectSensor == e.Sensor)
                    {
                        //   Clean();
                        MessageBox.Show("Kinect was disconnected");
                    }
                    break;
                case KinectStatus.NotReady:
                    MessageBox.Show("NotReady");
                    break;
                case KinectStatus.NotPowered:
                    if (kinectSensor == e.Sensor)
                    {
                        //   Clean();
                        MessageBox.Show("Kinect is no more powered");
                    }
                    break;
                default:
                    MessageBox.Show("Unhandled Status: " + e.Status);
                    break;
            }
        }
        void kinectRuntime_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (var frame = e.OpenColorImageFrame())
            {
                if (frame == null)
                    return;
                colorManager.Update(frame);
            }
        }
        void kinectSensor_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            using (var frame = e.OpenDepthImageFrame())
            {
                if (frame == null)
                    return;
                depthManager.Update(frame);
            }
        }
        void kinectRuntime_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            using (SkeletonFrame frame = e.OpenSkeletonFrame())
            {
                if (frame == null)
                    return;
                frame.GetSkeletons(ref skeletons);

                if (skeletons.All(s => s.TrackingState == SkeletonTrackingState.NotTracked))
                    return;
                ProcessFrame(frame);
                //    skeletonDisplayManager.Draw(skeletons,false);
            }
        }
        bool turn = true;
        void ProcessFrame(ReplaySkeletonFrame frame)
        {
            Dictionary<int, string> stabilities = new Dictionary<int, string>();
            foreach (var skeleton in frame.Skeletons)
            {
                if (skeleton.TrackingState != SkeletonTrackingState.Tracked)
                    continue;

                contextTracker.Add(skeleton.Position.ToVector3(), skeleton.TrackingId);
                stabilities.Add(skeleton.TrackingId,
                    contextTracker.IsStableRelativeToCurrentSpeed(skeleton.TrackingId) ? "Stable" : "Non stable");

                if (!contextTracker.IsStableRelativeToCurrentSpeed(skeleton.TrackingId))
                    continue;

                Vector3? HeadPostion = null;
                Vector3? LefthandPostion = null;
                Vector3? RighthandPostion = null;
                Vector3? ShoulderCenterPostion = null;

                Vector3? RightlegPostion = null;
                Vector3? LeftlegPostion = null;

                foreach (Joint joint in skeleton.Joints)
                {
                    switch (joint.JointType)
                    {
                        case JointType.HandRight:
                            RighthandPostion = joint.Position.ToVector3();
                            break;
                        case JointType.Head:
                            HeadPostion = joint.Position.ToVector3();
                            break;
                        case JointType.HandLeft:
                            LefthandPostion = joint.Position.ToVector3();
                            break;
                        case JointType.ShoulderCenter:
                            ShoulderCenterPostion = joint.Position.ToVector3();
                            break;
                        case JointType.FootRight:
                            RightlegPostion = joint.Position.ToVector3();
                            break;
                        case JointType.FootLeft:
                            LeftlegPostion = joint.Position.ToVector3();
                            break;
                    }
                }
                if (CheckJumpPosture(HeadPostion, RighthandPostion, LefthandPostion) && PlayerRect.IsGround)
                {
                    PlayerRect.IsJump = true;

                }
                else 
                {
                    
                }

                if (CheckTurnPosture(ShoulderCenterPostion, RighthandPostion))
                {
                    turn = true;
                }
                else if (CheckTurnPosture(ShoulderCenterPostion, LefthandPostion))
                {
                    turn = false;
                }
                
                if (CheckRunningPosture(RightlegPostion, LeftlegPostion))
                {
                    if (turn)
                    {
                        PlayerRect.IsRunning = true;
                        PlayerRect.IsBack = false;
                    }
                    else
                    {
                        PlayerRect.IsBack = true;
                        PlayerRect.IsRunning = false;
                    }
                }
                else
                {
                        PlayerRect.IsRunning = false;
                        PlayerRect.IsBack = false;
                }

                if (CheckAttackPosture(ShoulderCenterPostion, RighthandPostion, LefthandPostion))
                {
                    PlayerRect.IsAttack = true;
                }
            }
        }
        private bool CheckHandoverHead(Vector3? HeadPostion, Vector3? HandPostion)
        {
            if (!HeadPostion.HasValue || !HandPostion.HasValue)
                return false;
            if (HeadPostion.Value.Y > HandPostion.Value.Y)
                return false;
            return true;
        }
        private bool CheckJumpPosture(Vector3? HeadPostion, Vector3? RightHandPostion, Vector3? LeftHandPostion)
        {
            bool ROverHead = CheckHandoverHead(HeadPostion, RightHandPostion);
            bool LOverHead = CheckHandoverHead(HeadPostion, LeftHandPostion);

            if (ROverHead && LOverHead)
            {
                if (Math.Abs(RightHandPostion.Value.Y - LeftHandPostion.Value.Y) < 0.08)
                    return true;
            }
            return false;
        }
        bool prepare = false;

        private bool CheckAttackPosture(Vector3? ShoulderCenterPostion, Vector3? RightHandPostion, Vector3? LeftHandPostion)
        {
            if (prepare)
            {

                if ((Math.Abs(ShoulderCenterPostion.Value.Z - LeftHandPostion.Value.Z) > 0.5)
                      && (Math.Abs(ShoulderCenterPostion.Value.Y - LeftHandPostion.Value.Y) < 0.2))
                {
                    prepare = false;
                    return true;
                }
                else if ((Math.Abs(ShoulderCenterPostion.Value.Z - RightHandPostion.Value.Z) > 0.55)
                     && (Math.Abs(ShoulderCenterPostion.Value.Y - RightHandPostion.Value.Y) < 0.2))
                {
                    prepare = false;
                    return true;
                }
                else
                {
                    return false;
                }

            }
            else
            {
                if (Math.Abs(ShoulderCenterPostion.Value.Z - LeftHandPostion.Value.Z) < 0.4
                    && Math.Abs(ShoulderCenterPostion.Value.Z - RightHandPostion.Value.Z) < 0.4
                    && (Math.Abs(ShoulderCenterPostion.Value.Y - LeftHandPostion.Value.Y) < 0.2)
                    && (Math.Abs(ShoulderCenterPostion.Value.Y - RightHandPostion.Value.Y) < 0.2))
                {
                    prepare = true;
                }

                return false;
            }
        }
        int cout=0;
        private bool CheckRunningPosture(Vector3? RightlegPostion, Vector3? LeftlegPostion)
        {
            if (Math.Abs(RightlegPostion.Value.Y - LeftlegPostion.Value.Y) > 0.12)
            {
                cout = 0;
                return true;
            }
            else
            {
                    cout++;
                    if (cout > 30)
                    {   
                        return false;
                    }
                    else
                        return true;
            }
        }
        private bool CheckTurnPosture(Vector3? ShoulderCenterPostion, Vector3? RightHandPostion)
        {
            if (Math.Abs(RightHandPostion.Value.Z - ShoulderCenterPostion.Value.Z) < 0.3 && Math.Abs(RightHandPostion.Value.Y - ShoulderCenterPostion.Value.Y) < 0.4
                && Math.Abs(RightHandPostion.Value.X - ShoulderCenterPostion.Value.X) > 0.6)
            {
                return true;
            }
            return false;
        }
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Clean();
        }
        private void Clean()
        {
            if (kinectSensor != null)
            {
                kinectSensor.ColorFrameReady -= kinectRuntime_ColorFrameReady;
                kinectSensor.Stop();
                kinectSensor = null;
            }
        }
    }
}